package main

import (
	"context"
	"errors"
	"fmt"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"

	"gitee.com/zawei/yggdrasil/pkg/lib/omega"
	"gitee.com/zawei/yggdrasil/pkg/log"
)

var (
	lock                           = sync.Mutex{}
	BALANCES                       map[string]int
	TransferMoneyTccStartDecorated func(ctx context.Context, i int) error
	TransferOutPartitionDecorated  func(ctx context.Context, i int, from string, amount int) error
	TransferInPartitionDecorated   func(ctx context.Context, i int, to string, amount int) error
	TransferMoneySagaEndDecorated  func(ctx context.Context) error

	params = make(map[string][]interface{})
)

func init() {
	err := omega.DecorateTccMethod(&TransferMoneyTccStartDecorated, TransferMoney, true)
	if err != nil {
		panic(err)
	}
	err = omega.DecoratePartitionMethod(&TransferOutPartitionDecorated, TransferOut, ConfirmTransferOut, CancelTransferOut)
	if err != nil {
		panic(err)
	}
	err = omega.DecoratePartitionMethod(&TransferInPartitionDecorated, TransferInTry, ConfirmTransferIn, CancelTransferIn)
	if err != nil {
		panic(err)
	}
	err = omega.DecorateTccEndMethod(&TransferMoneySagaEndDecorated, TransferMoneyEnd)
	if err != nil {
		panic(err)
	}
	initDatas()
}

func initDatas() {
	BALANCES = make(map[string]int, 0)
	BALANCES["foo"] = 500
	BALANCES["bar"] = 500
}

func TransferMoneyEnd(ctx context.Context) error {
	return nil
}

func TransferMoney(ctx context.Context, i int) error {
	err := TransferOutPartitionDecorated(ctx, i, "foo", 100)
	if err != nil {
		return err
	}
	err = TransferInPartitionDecorated(ctx, i, "bar", 100)
	if err != nil {
		return err
	}
	return nil
}

func TransferOut(ctx context.Context, i int, from string, amount int) error {
	lock.Lock()
	defer lock.Unlock()
	localID, ok := omega.GetLocalIdFromContext(ctx)
	if !ok {
		return errors.New("not omega context")
	}
	params[localID] = []interface{}{i, from, amount}
	oldAmount, _ := BALANCES[from]
	if oldAmount < amount {
		delete(params, localID)
		return errors.New("balance fff")
	}
	BALANCES[from] = oldAmount - amount
	return nil
}

func ConfirmTransferOut(ctx context.Context) error {
	fmt.Print("ConfirmTransferOut ")
	fmt.Println(omega.GetAllFromContext(ctx))

	return nil
}

func CancelTransferOut(ctx context.Context) error {
	fmt.Print("CancelTransferOut ")
	fmt.Println(omega.GetAllFromContext(ctx))

	localID, ok := omega.GetLocalIdFromContext(ctx)
	if !ok {
		return errors.New("not omega context")
	}
	args, ok := params[localID]
	if !ok {
		return nil
	}
	from := args[1].(string)
	amount := args[2].(int)

	lock.Lock()
	defer lock.Unlock()
	oldAmount, _ := BALANCES[from]
	BALANCES[from] = oldAmount + amount
	return nil
}

func TransferInTry(ctx context.Context, i int, to string, amount int) error {
	//localID, ok := omega.GetLocalIdFromContext(ctx)
	//if !ok {
	//	return errors.New("not omega context")
	//}
	//params[localID] = []interface{}{i, to, amount}
	return errors.New("xxx")
}

func ConfirmTransferIn(ctx context.Context) error {
	fmt.Print("ConfirmTransferIn ")
	fmt.Println(omega.GetAllFromContext(ctx))

	localID, ok := omega.GetLocalIdFromContext(ctx)
	if !ok {
		return errors.New("not omega context")
	}
	args := params[localID]
	to := args[1].(string)
	amount := args[2].(int)

	lock.Lock()
	defer lock.Unlock()
	oldAmount, _ := BALANCES[to]
	BALANCES[to] = oldAmount + amount
	return nil
}

func CancelTransferIn(ctx context.Context) error {
	fmt.Print("CancelTransferIn ")
	fmt.Println(omega.GetAllFromContext(ctx))
	lock.Lock()
	defer lock.Unlock()

	return nil
}

func main() {
	cfg := &omega.Config{
		Transport: omega.TransportConfig{
			ServiceName: "omega",
			InstanceId:  "omega-123456",
			GrcpClient:  omega.GrpcClientConfig{Target: "localhost:18080"},
		},
		AkkaEnabled: true,
	}
	cfg.WithLogger((&zap.Config{Level: "debug"}).Build())
	// 这里的第一个参数是本服务的名称，第二个参数是alpha-server的地址，第三个参数是Logger
	if err := omega.InitOmega(context.Background(), cfg); err != nil {
		panic(err)
	}
	fmt.Printf("foo balance: %d, bar balance: %d\n", BALANCES["foo"], BALANCES["bar"])
	stopped := false
	if err := TransferMoneyTccStartDecorated(context.TODO(), 0); err != nil {
		fmt.Println(err.Error())
	}

	fmt.Printf("foo balance: %d, bar balance: %d\n", BALANCES["foo"], BALANCES["bar"])

	go func() {
		s := make(chan os.Signal)
		signal.Notify(s, syscall.SIGINT, syscall.SIGTERM)
		<-s
		omega.CloseOmega()
		stopped = true
	}()
	for !stopped {
		fmt.Printf("222 foo balance: %d, bar balance: %d\n", BALANCES["foo"], BALANCES["bar"])
		time.Sleep(time.Second * 3)
	}
}
